/* NOTICE
    OpenJaWS - Open Java Weather Station
    
    Copyright (C) 2008 Grant Gardner <grant@lastweekend.com.au>
    
    OpenJaWS is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    
NOTICE */

package au.com.lastweekend.ws2300;

import java.io.IOException;
import java.util.Calendar;
import java.util.Date;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import au.com.lastweekend.openjaws.util.LoopRunnable;
import au.com.lastweekend.ws2300.WS2300.HistoryInfo;

/**
 * This class tries to behave like the real thing
 * <p>
 * Starts a collection of threads (Just a clock at the moment), to simulate the various goings on inside the station (which seems
 * to be multi-threaded)
 * <p>
 * Ultimately could simulate sensor values.
 * 
 * @author ggardner
 * 
 */
public class WS2300Simulator {

    private static final Logger LOG = LoggerFactory.getLogger(WS2300Simulator.class);

    private int timeWarp = 1000;

    private WS2300 ws2300;

    private ClockRunnable clockRunnable;

    /**
     * Note this clock is deliberately inaccurate like the real device!!
     * 
     * @author ggardner
     * 
     */
    public class ClockRunnable extends LoopRunnable {

        @Override
        protected void preLoop() {

            try {
                ws2300.setCurrentTime(new Date());
            } catch (IOException e) {
                LOG.error("Error initialising time", e);
            }
        }

        @Override
        protected void inLoop() {

            try {
                Calendar cal = ws2300.getCalendarTime();
                cal.add(Calendar.SECOND, 1);

                LOG.debug(String.format("Time: %tc", cal));

                ws2300.setTime(MemoryMap.TIME_UTC, cal);

                if (cal.get(Calendar.SECOND) == 0) {
                    ws2300.setTime(MemoryMap.TIME_LOCAL, cal);
                    decrementHistoryCounter();
                }
                Thread.sleep(delay());

            } catch (InterruptedException e) {
                LOG.debug("Interrupted", e);
            } catch (IOException e1) {
                LOG.error("Error doing the simulator thing", e1);
            }

        }

        protected int delay() {

            return timeWarp;
        }

        private void decrementHistoryCounter() throws IOException {

            HistoryInfo histInfo = ws2300.getHistoryInfo();
            int minutesToNextReading = histInfo.getMinutesToNextReading();
            minutesToNextReading--;
            if (minutesToNextReading <= 0) {
                minutesToNextReading = histInfo.getInterval();
            }
            ws2300.resetHistoryInfo(histInfo.getInterval(), minutesToNextReading, false);

        }

    }

    public WS2300Simulator(WS2300 ws2300) {

        this.ws2300 = ws2300;
        this.clockRunnable = new ClockRunnable();

    }

    /**
     * The number of real milliseconds to use to drive the clock
     * 
     * @param timeWarp
     */
    public void setTimeWarp(int timeWarp) {

        this.timeWarp = timeWarp;
    }

    public void stop() {

        clockRunnable.stop();
    }

    public void start() {

        clockRunnable.start("WS2300-Simulator.Clock");

    }

    public void stopAtShutDown() {

        clockRunnable.stopAtShutdown();
    }
}
